library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity shift_reg is
  port ( clk   : in  std_ulogic;
		 cpld_clk : in std_ulogic;
         reset : in  std_ulogic;
         data : in std_ulogic;
         outp  : out std_logic_vector ( 7 downto 0 );
         outflag : out std_ulogic;
         outerror : out std_ulogic);
end shift_reg;

architecture rtl of shift_reg is

  subtype counter_range is integer range 0 to 12;
  signal shift_reg : std_logic_vector ( 7 downto 0 );
  signal count_int : counter_range;
  signal clockCount : counter_range;
  signal dataReadyFlag : std_ulogic;
  signal ps2LastClock : std_ulogic;
  signal ps2LastData : std_ulogic;
  signal lastGoodEdge : std_ulogic;
  signal errorFlag : std_ulogic;
  signal FallEdgeDone : std_ulogic;
  
begin

  outflag <= dataReadyFlag;
  outerror <= errorFlag;
  outp <= shift_reg;
  
  filter : process (cpld_clk, reset)
  begin
	if (Reset='1') then
		ps2LastClock <= '0';
		clockCount <= 0;
	elsif (rising_edge (cpld_clk)) then
		if (FallEdgeDone = '0') then
			clockCount <= 0;
		elsif (clk=ps2LastClock) then 
			clockCount <= clockCount + 1;
		else
			clockCount <= 0;
		end if;
		ps2LastData <= data;
		ps2LastClock <= clk;
	end if;		
  end process filter;

  shifter : process ( cpld_clk, reset)
  begin
	if (Reset='1') then
		lastGoodEdge <= '0';
		count_int <= 0;
		FallEdgeDone <= '0';
	elsif (rising_edge (cpld_clk)) then
		if (clockCount = 8) then --8 cons. clocks
			if (ps2LastClock = '1') then
				lastGoodEdge <= '1';
			elsif ((lastGoodEdge = '1') and (ps2LastClock = '0')) then --falling edge
				if (count_int = 0) then --start bit [0]
					errorFlag <= ps2LastData;
					count_int <= count_int +1;
					dataReadyFlag <= '0';
				elsif (count_int = 9) then --parity bit [9]
					count_int <= count_int +1;
				elsif (count_int = 10) then --stop bit [10]
					errorFlag <= not(ps2LastData);
					count_int <= 0;
					dataReadyFlag <= '1';
				else --data bits [1...8]
					count_int <= count_int +1;
					shift_reg <= ps2LastData & shift_reg(7 downto 1);
				end if;
				lastGoodEdge <= '0';
			end if; --end falling edge
			FallEdgeDone <= '1';
		else
			FallEdgeDone <= '0';
		end if; -- end 8 cons. clocks
	end if;
  end process shifter;

end rtl;